/**
 * Copyright 2019-2022 Huawei Technologies Co., Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "hiai_tensor_aipp_para_util.h"

#include "framework/infra/log/log.h"

#define HIAI_EXPECT_NOT_NULL_R(ptr, ret) \
    if ((ptr) == NULL) { \
        return ret; \
    }

static const uint8_t MAX_CSC_MATRIX_PARA_NUM = 15;
static const uint8_t MAX_BATCH_NUM = 127;
static const uint8_t MAX_CHANNEL_NUM = 4;

enum CceAippInputFormat {
    CCE_YUV420SP_U8 = 1,
    CCE_XRGB8888_U8,
    CCE_NC1HWC0DI_FP16,
    CCE_NC1HWC0DI_S8,
    CCE_RGB888_U8,
    CCE_ARGB8888_U8,
    CCE_YUYV_U8,
    CCE_YUV422SP_U8,
    CCE_AYUV444_U8,
    CCE_YUV400_U8,
    CCE_RESERVED
};

static uint16_t SaveFp16ToUint16(_Float16 num)
{
    uint16_t* uintAddr = NULL;
    uintAddr = (uint16_t*)(void*)(&num);
    return *uintAddr;
}

static _Float16 SaveUint16ToFp16(uint16_t num)
{
    _Float16* uintAddr = NULL;
    uintAddr = (_Float16*)(void*)(&num);
    return *uintAddr;
}

int32_t HIAI_TensorAippUtil_GetRawBufferSize(void* commPara)
{
    HIAI_MR_TensorAippCommPara* data = (HIAI_MR_TensorAippCommPara*)(commPara);
    HIAI_EXPECT_NOT_NULL_R(data, 0);

    return sizeof(HIAI_MR_TensorAippCommPara) + sizeof(HIAI_MR_TensorAippBatchPara) * data->batchNum;
}

HIAI_Status HIAI_TensorAippUtil_SetBatchCount(void* commPara, uint32_t batchNum)
{
    HIAI_MR_TensorAippCommPara* data = (HIAI_MR_TensorAippCommPara*)(commPara);
    HIAI_EXPECT_NOT_NULL_R(data, HIAI_FAILURE);
    data->batchNum = (uint8_t)(batchNum);
    return HIAI_SUCCESS;
}

uint32_t HIAI_TensorAippUtil_GetBatchCount(void* commPara)
{
    HIAI_MR_TensorAippCommPara* data = (HIAI_MR_TensorAippCommPara*)(commPara);
    HIAI_EXPECT_NOT_NULL_R(data, HIAI_FAILURE);

    return data->batchNum;
}

HIAI_MR_TensorAippBatchPara* HIAI_TensorAippUtil_GetBatchPara(void* commPara, uint32_t batchIndex)
{
    HIAI_MR_TensorAippCommPara* data = (HIAI_MR_TensorAippCommPara*)(commPara);
    HIAI_EXPECT_NOT_NULL_R(data, NULL);

    if (data->batchNum > MAX_BATCH_NUM || batchIndex >= data->batchNum) {
        return NULL;
    }

    return (HIAI_MR_TensorAippBatchPara*)(void*)((char*)(commPara) +
        sizeof(HIAI_MR_TensorAippCommPara) + sizeof(HIAI_MR_TensorAippBatchPara) * batchIndex);
}

bool HIAI_TensorAippUtil_GetCscSwitch(void* commPara)
{
    HIAI_MR_TensorAippCommPara* data = (HIAI_MR_TensorAippCommPara*)(commPara);
    HIAI_EXPECT_NOT_NULL_R(data, false);
    return data->cscSwitch > 0;
}

bool HIAI_TensorAippUtil_GetCropSwitch(void* commPara, uint32_t batchIndex)
{
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, false);
    return batchPara->cropSwitch > 0;
}

bool HIAI_TensorAippUtil_GetResizeSwitch(void* commPara, uint32_t batchIndex)
{
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, false);
    return batchPara->scfSwitch > 0;
}

bool HIAI_TensorAippUtil_GetPadSwitch(void* commPara, uint32_t batchIndex)
{
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, false);
    return batchPara->paddingSwitch > 0;
}

HIAI_Status HIAI_TensorAippUtil_SetInputFormat(void* commPara, HIAI_ImageFormat inputFormat)
{
    HIAI_MR_TensorAippCommPara* data = (HIAI_MR_TensorAippCommPara*)(commPara);
    HIAI_EXPECT_NOT_NULL_R(data, HIAI_FAILURE);

    switch (inputFormat) {
        case HIAI_YUV420SP_U8 :
            data->inputFormat = (uint8_t)(CCE_YUV420SP_U8);
            break;
        case HIAI_XRGB8888_U8 :
            data->inputFormat = (uint8_t)(CCE_XRGB8888_U8);
            break;
        case HIAI_ARGB8888_U8 :
            data->inputFormat = (uint8_t)(CCE_ARGB8888_U8);
            break;
        case HIAI_YUYV_U8 :
            data->inputFormat = (uint8_t)(CCE_YUYV_U8);
            break;
        case HIAI_YUV422SP_U8 :
            data->inputFormat = (uint8_t)(CCE_YUV422SP_U8);
            break;
        case HIAI_AYUV444_U8 :
            data->inputFormat = (uint8_t)(CCE_AYUV444_U8);
            break;
        case HIAI_YUV400_U8 :
            data->inputFormat = (uint8_t)(CCE_YUV400_U8);
            break;
        case HIAI_RGB888_U8 :
            data->inputFormat = (uint8_t)(CCE_RGB888_U8);
            break;
        default:
            FMK_LOGE("Unknown inputFormat: %d", inputFormat);
            return HIAI_FAILURE;
    }

    return HIAI_SUCCESS;
}

HIAI_ImageFormat HIAI_TensorAippUtil_GetInputFormat(void* commPara)
{
    HIAI_MR_TensorAippCommPara* data = (HIAI_MR_TensorAippCommPara*)(commPara);
    HIAI_EXPECT_NOT_NULL_R(data, HIAI_IMAGE_FORMAT_INVALID);

    switch (data->inputFormat) {
        case CCE_YUV420SP_U8 :
            return HIAI_YUV420SP_U8;
        case CCE_XRGB8888_U8 :
            return HIAI_XRGB8888_U8;
        case CCE_ARGB8888_U8 :
            return HIAI_ARGB8888_U8;
        case CCE_YUYV_U8 :
            return HIAI_YUYV_U8;
        case CCE_YUV422SP_U8 :
            return HIAI_YUV422SP_U8;
        case CCE_AYUV444_U8 :
            return HIAI_AYUV444_U8;
        case CCE_YUV400_U8 :
            return HIAI_YUV400_U8;
        case CCE_RGB888_U8 :
            return HIAI_RGB888_U8;
        default:
            FMK_LOGE("Unknown cce inputFormat: %d", data->inputFormat);
            return HIAI_IMAGE_FORMAT_INVALID;
    }

    return HIAI_IMAGE_FORMAT_INVALID;
}

HIAI_Status HIAI_TensorAippUtil_SetInputShape(void* commPara, uint32_t srcImageW, uint32_t srcImageH)
{
    HIAI_MR_TensorAippCommPara* data = (HIAI_MR_TensorAippCommPara*)(commPara);
    HIAI_EXPECT_NOT_NULL_R(data, HIAI_FAILURE);

    data->srcImageSizeW = (int32_t)(srcImageW);
    data->srcImageSizeH = (int32_t)(srcImageH);
    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_GetInputShape(void* commPara, uint32_t* srcImageW, uint32_t* srcImageH)
{
    HIAI_MR_TensorAippCommPara* data = (HIAI_MR_TensorAippCommPara*)(commPara);
    HIAI_EXPECT_NOT_NULL_R(data, HIAI_FAILURE);
    if (srcImageW == NULL || srcImageH == NULL) {
        return HIAI_FAILURE;
    }

    *srcImageW = (uint32_t)(data->srcImageSizeW);
    *srcImageH = (uint32_t)(data->srcImageSizeH);
    return HIAI_SUCCESS;
}

struct FormatMap {
    HIAI_ImageFormat imageFormat;
    const char* formatStr;
};

static const char* FormatToStr(HIAI_ImageFormat format)
{
    const struct FormatMap strMap[11] = {
        {HIAI_YUV420SP_U8, "YUV420SP_U8"},
        {HIAI_XRGB8888_U8, "XRGB8888_U8"},
        {HIAI_YUV400_U8, "YUV400_U8"},
        {HIAI_ARGB8888_U8, "ARGB8888_U8"},
        {HIAI_YUYV_U8, "YUYV_U8"},
        {HIAI_YUV422SP_U8, "YUV422SP_U8"},
        {HIAI_AYUV444_U8, "AYUV444_U8"},
        {HIAI_RGB888_U8, "RGB888_U8"},
        {HIAI_BGR888_U8, "BGR888_U8"},
        {HIAI_YUV444SP_U8, "YUV444SP_U8"},
        {HIAI_YVU444SP_U8, "YVU444SP_U8"},
    };
    const char* undefinedStr = "undefined";
    for (size_t i = 0; i < 11; i++) {
        if (strMap[i].imageFormat == format) {
            return strMap[i].formatStr;
        }
    }
    return undefinedStr;
}

struct Pair {
    HIAI_ImageFormat imageFormat;
    uint32_t idxList[3];
};

const static int YUV_TO_RGB[4][3][3] = {{{256, 0, 359}, {256, -88, -183}, {256, 454, 0}},
    {{298, 0, 409}, {298, -100, -208}, {298, 516, 0}}, {{256, 0, 359}, {256, -88, -183}, {256, 454, 0}},
    {{298, 0, 460}, {298, -55, -137}, {298, 541, 0}}};

const static int RGB_TO_YUV[4][3][3] = {{{77, 150, 29}, {-43, -85, 128}, {128, -107, -21}},
    {{66, 129, 25}, {-38, -74, 112}, {112, -94, -18}}, {{77, 150, 29}, {-43, -85, 128}, {128, -107, -21}},
    {{47, 157, 16}, {-26, -87, 112}, {112, -102, -10}}};

static int32_t InitCscMatrixToRGB(HIAI_ImageFormat inputFormat, HIAI_ImageFormat targetFormat,
    int32_t cscValues[], uint8_t inputBiasValues[], HIAI_ImageColorSpace imageType)
{
    if (inputFormat == HIAI_XRGB8888_U8 || inputFormat == HIAI_RGB888_U8 ||
        inputFormat == HIAI_ARGB8888_U8 || inputFormat == HIAI_BGR888_U8 ||
        inputFormat == HIAI_YUV400_U8) {
        FMK_LOGE("Set SetCscPara failed, can not convert from %s image to %s by CSC", FormatToStr(inputFormat),
            FormatToStr(targetFormat));
        return -1;
    }
    const static struct Pair idxPair1[2] = {{HIAI_RGB888_U8, {0, 1, 2}}, {HIAI_BGR888_U8, {2, 1, 0}}};
    uint32_t step = 0;
    for (int i = 0; i < 2; i++) {
        if (idxPair1[i].imageFormat != targetFormat) {
            continue;
        }
        for (uint32_t t = 0; t < 3; t++) {
            uint32_t idx = idxPair1[i].idxList[t];
            for (uint32_t j = 0; j < 3; ++j) {
                cscValues[step++] = YUV_TO_RGB[(uint32_t)(imageType)][idx][j];
            }
        }
    }
    inputBiasValues[0] = imageType == HIAI_JPEG ? 0 : 16;
    inputBiasValues[1] = 128;
    inputBiasValues[2] = 128;
    return 0;
}

static int32_t InitCscMatrixToYUV(HIAI_ImageFormat inputFormat, HIAI_ImageFormat targetFormat,
    int32_t cscValues[], uint8_t outputBiasValues[], HIAI_ImageColorSpace imageType)
{
    if (inputFormat == HIAI_YUV420SP_U8 || inputFormat == HIAI_YUV422SP_U8 ||
        inputFormat == HIAI_YUYV_U8 || inputFormat == HIAI_AYUV444_U8 || inputFormat == HIAI_YUV400_U8) {
        FMK_LOGE("Set SetCscPara failed, can not convert from %s image to %s by CSC", FormatToStr(inputFormat),
            FormatToStr(targetFormat));
        return -1;
    }
    const static struct Pair idxPair2[2] = {{HIAI_YUV444SP_U8, {0, 1, 2}}, {HIAI_YVU444SP_U8, {0, 2, 1}}};
    uint32_t step = 0;
    for (uint32_t idx = 0; idx < 2; idx++) {
        if (targetFormat == idxPair2[idx].imageFormat) {
            for (uint32_t j = 0; j < 3; ++j) {
                cscValues[step++] = RGB_TO_YUV[(uint32_t)(imageType)][idx][j];
            }
        }
    }
    outputBiasValues[0] = imageType == HIAI_JPEG ? 0 : 16;
    outputBiasValues[1] = 128;
    outputBiasValues[2] = 128;
    return 0;
}

static int32_t InitCscMatrixToGray(HIAI_ImageFormat inputFormat, int32_t cscValues[])
{
    if (inputFormat == HIAI_YUV400_U8) {
        FMK_LOGE("Set SetCscPara failed, can not convert from %s image to YUV400_U8 by CSC",
            FormatToStr(inputFormat));
        return -1;
    } else if (inputFormat == HIAI_YUV420SP_U8 || inputFormat == HIAI_YUV422SP_U8 ||
        inputFormat == HIAI_YUYV_U8 || inputFormat == HIAI_AYUV444_U8) { // YUV images
        cscValues[0] = 256;
    } else { // RGB images
        cscValues[0] = 76;
        cscValues[1] = 150;
        cscValues[2] = 30;
    }
    return 0;
}

HIAI_Status HIAI_TensorAippUtil_SetCscPara(void* commPara, HIAI_ImageFormat inputFormat,
    HIAI_ImageFormat targetFormat, HIAI_ImageColorSpace colorSpace)
{
    HIAI_MR_TensorAippCommPara* data = (HIAI_MR_TensorAippCommPara*)(commPara);
    HIAI_EXPECT_NOT_NULL_R(data, HIAI_FAILURE);

    if (targetFormat != HIAI_YVU444SP_U8 && targetFormat != HIAI_YUV444SP_U8 && targetFormat != HIAI_RGB888_U8 &&
        targetFormat != HIAI_BGR888_U8 && targetFormat != HIAI_YUV400_U8) {
        FMK_LOGE("outputFormat is out of valid  range of [ YVU444SP, YUV444SP, BGR888, BGR888, YUV400 ]");
        return HIAI_FAILURE;
    }

    int32_t cscValues[9] = {0};
    uint8_t inputBiasValues[3] = {0};
    uint8_t outputBiasValues[3] = {0};
    int32_t ret = -1;
    if (targetFormat == HIAI_RGB888_U8 || targetFormat == HIAI_BGR888_U8) {
        ret = InitCscMatrixToRGB(inputFormat, targetFormat, cscValues, inputBiasValues, colorSpace);
    } else if (targetFormat == HIAI_YUV444SP_U8 || targetFormat == HIAI_YVU444SP_U8) {
        ret = InitCscMatrixToYUV(inputFormat, targetFormat, cscValues, outputBiasValues, colorSpace);
    } else {
        ret = InitCscMatrixToGray(inputFormat, cscValues);
    }
    if (ret != 0) {
        return HIAI_FAILURE;
    }

    data->reserve1[1] = (unsigned int)(targetFormat); // outputFormat
    data->reserve1[2] = (unsigned int)(colorSpace); // corlorSpace

    data->cscSwitch = true;
    data->cscMatrixR0C0 = cscValues[0];
    data->cscMatrixR0C1 = cscValues[1];
    data->cscMatrixR0C2 = cscValues[2];
    data->cscMatrixR1C0 = cscValues[3];
    data->cscMatrixR1C1 = cscValues[4];
    data->cscMatrixR1C2 = cscValues[5];
    data->cscMatrixR2C0 = cscValues[6];
    data->cscMatrixR2C1 = cscValues[7];
    data->cscMatrixR2C2 = cscValues[8];
    data->cscInputBiasR0 = inputBiasValues[0];
    data->cscInputBiasR1 = inputBiasValues[1];
    data->cscInputBiasR2 = inputBiasValues[2];
    data->cscOutputBiasR0 = outputBiasValues[0];
    data->cscOutputBiasR1 = outputBiasValues[1];
    data->cscOutputBiasR2 = outputBiasValues[2];
    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_SetCscMatrixPara(void* commPara, int32_t cscMatrixPara[], uint32_t paraNum)
{
    HIAI_EXPECT_NOT_NULL_R(cscMatrixPara, HIAI_FAILURE);
    HIAI_MR_TensorAippCommPara* data = (HIAI_MR_TensorAippCommPara*)(commPara);
    HIAI_EXPECT_NOT_NULL_R(data, HIAI_FAILURE);
    if (paraNum == 0 || paraNum > MAX_CSC_MATRIX_PARA_NUM) {
        return HIAI_FAILURE;
    }

    int16_t tmpCscMatrix[9] = {0}; // array size of cscMatrix is 9
    for (uint32_t i = 0; i < 9; i++) { // array size of cscMatrix is 9
        if (i < paraNum) {
            tmpCscMatrix[i] = (int16_t)(cscMatrixPara[i]);
        } else {
            tmpCscMatrix[i] = 0; // default value is 0
        }
    }
    uint8_t tmpCscBiasParas[6] = {0};
    for (uint32_t i = 0; i < 6; i++) { // array size of cscBiasParas is 6
        if (i + 9 < paraNum) {
            tmpCscBiasParas[i] = (uint8_t)(cscMatrixPara[9 + i]);
        } else {
            tmpCscBiasParas[i] = 0; // default value is 0
        }
    }

    data->cscSwitch = true;
    data->cscMatrixR0C0 = tmpCscMatrix[0];
    data->cscMatrixR0C1 = tmpCscMatrix[1];
    data->cscMatrixR0C2 = tmpCscMatrix[2];
    data->cscMatrixR1C0 = tmpCscMatrix[3];
    data->cscMatrixR1C1 = tmpCscMatrix[4];
    data->cscMatrixR1C2 = tmpCscMatrix[5];
    data->cscMatrixR2C0 = tmpCscMatrix[6];
    data->cscMatrixR2C1 = tmpCscMatrix[7];
    data->cscMatrixR2C2 = tmpCscMatrix[8];
    data->cscInputBiasR0 = tmpCscBiasParas[0];
    data->cscInputBiasR1 = tmpCscBiasParas[1];
    data->cscInputBiasR2 = tmpCscBiasParas[2];
    data->cscOutputBiasR0 = tmpCscBiasParas[3];
    data->cscOutputBiasR1 = tmpCscBiasParas[4];
    data->cscOutputBiasR2 = tmpCscBiasParas[5];
    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_GetCscPara(void* commPara, HIAI_ImageFormat* inputFormat,
    HIAI_ImageFormat* targetFormat, HIAI_ImageColorSpace* colorSpace)
{
    HIAI_MR_TensorAippCommPara* data = (HIAI_MR_TensorAippCommPara*)(commPara);
    HIAI_EXPECT_NOT_NULL_R(data, HIAI_FAILURE);
    if (inputFormat == NULL || targetFormat == NULL || colorSpace == NULL) {
        return HIAI_FAILURE;
    }

    *inputFormat  = HIAI_TensorAippUtil_GetInputFormat(commPara);
    *targetFormat = (HIAI_ImageFormat)(data->reserve1[1]);
    *colorSpace = (HIAI_ImageColorSpace)(data->reserve1[2]);
    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_GetCscMatrixPara(void* commPara, int32_t cscMatrixPara[], uint32_t paraNum)
{
    HIAI_EXPECT_NOT_NULL_R(cscMatrixPara, HIAI_FAILURE);
    HIAI_MR_TensorAippCommPara* data = (HIAI_MR_TensorAippCommPara*)(commPara);
    HIAI_EXPECT_NOT_NULL_R(data, HIAI_FAILURE);
    if (paraNum == 0 || paraNum > MAX_CSC_MATRIX_PARA_NUM) {
        return HIAI_FAILURE;
    }
    int16_t tmpCscMatrix[9] = { // array size of cscMatrix is 9
        data->cscMatrixR0C0, data->cscMatrixR0C1, data->cscMatrixR0C2,
        data->cscMatrixR1C0, data->cscMatrixR1C1, data->cscMatrixR1C2,
        data->cscMatrixR2C0, data->cscMatrixR2C1, data->cscMatrixR2C2
    };
    uint8_t tmpCscBiasParas[6] = { // array size of cscBiasParas is 6
        data->cscInputBiasR0, data->cscInputBiasR1, data->cscInputBiasR2,
        data->cscOutputBiasR0, data->cscOutputBiasR1, data->cscOutputBiasR2
    };
    for (uint32_t i = 0; i < paraNum; i++) {
        if (i < 9) { // array size of cscMatrix is 9
            cscMatrixPara[i] = tmpCscMatrix[i];
        } else {
            cscMatrixPara[i] = tmpCscBiasParas[i - 9]; // array size of cscMatrix is 9
        }
    }
    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_SetChannelSwapPara(void* commPara, bool rbuvSwapSwitch, bool axSwapSwitch)
{
    HIAI_MR_TensorAippCommPara* data = (HIAI_MR_TensorAippCommPara*)(commPara);
    HIAI_EXPECT_NOT_NULL_R(data, HIAI_FAILURE);

    data->rbuvSwapSwitch = (rbuvSwapSwitch ? 1 : 0);
    data->axSwapSwitch = (axSwapSwitch ? 1 : 0);
    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_GetChannelSwapPara(void* commPara, bool* rbuvSwapSwitch, bool* axSwapSwitch)
{
    HIAI_MR_TensorAippCommPara* data = (HIAI_MR_TensorAippCommPara*)(commPara);
    HIAI_EXPECT_NOT_NULL_R(data, HIAI_FAILURE);
    if (rbuvSwapSwitch == NULL || axSwapSwitch == NULL) {
        return HIAI_FAILURE;
    }

    *rbuvSwapSwitch = data->rbuvSwapSwitch > 0 ? true : false;
    *axSwapSwitch = data->axSwapSwitch > 0 ? true : false;
    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_SetSingleBatchMultiCrop(void* commPara, bool singleBatchMutiCrop)
{
    HIAI_MR_TensorAippCommPara* data = (HIAI_MR_TensorAippCommPara*)(commPara);
    HIAI_EXPECT_NOT_NULL_R(data, HIAI_FAILURE);

    data->reserve1[0] = singleBatchMutiCrop ? 1 : 0;
    return HIAI_SUCCESS;
}

bool HIAI_TensorAippUtil_GetSingleBatchMultiCrop(void* commPara)
{
    HIAI_MR_TensorAippCommPara* data = (HIAI_MR_TensorAippCommPara*)(commPara);
    HIAI_EXPECT_NOT_NULL_R(data, false);

    return (data->reserve1[0] == 0) ? false : true;
}

HIAI_Status HIAI_TensorAippUtil_SetCropPos(
    void* commPara, uint32_t batchIndex, uint32_t cropStartPosW, uint32_t cropStartPosH)
{
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);

    batchPara->cropSwitch = 1;
    batchPara->cropStartPosW = cropStartPosW;
    batchPara->cropStartPosH = cropStartPosH;
    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_SetCropSize(void* commPara, uint32_t batchIndex, uint32_t cropSizeW, uint32_t cropSizeH)
{
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);

    batchPara->cropSwitch = 1;
    batchPara->cropSizeW = cropSizeW;
    batchPara->cropSizeH = cropSizeH;
    if (batchPara->scfSwitch != 0) {
        batchPara->scfInputSizeW = (int32_t)(batchPara->cropSizeW);
        batchPara->scfInputSizeH = (int32_t)(batchPara->cropSizeH);
    }
    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_GetCropPos(
    void* commPara, uint32_t batchIndex, uint32_t* cropStartPosW, uint32_t* cropStartPosH)
{
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);
    if (cropStartPosW == NULL || cropStartPosH == NULL) {
        return HIAI_FAILURE;
    }

    *cropStartPosW = batchPara->cropStartPosW;
    *cropStartPosH = batchPara->cropStartPosH;

    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_GetCropSize(
    void* commPara, uint32_t batchIndex, uint32_t* cropSizeW, uint32_t* cropSizeH)
{
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);
    if (cropSizeW == NULL || cropSizeH == NULL) {
        return HIAI_FAILURE;
    }

    *cropSizeW = batchPara->cropSizeW;
    *cropSizeH = batchPara->cropSizeH;

    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_SetResizePara(void* commPara,
    uint32_t batchIndex, uint32_t resizeOutputSizeW, uint32_t resizeOutputSizeH)
{
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);
    HIAI_MR_TensorAippCommPara* data = (HIAI_MR_TensorAippCommPara*)(commPara);
    HIAI_EXPECT_NOT_NULL_R(data, HIAI_FAILURE);
    batchPara->scfInputSizeH = ((batchPara->cropSwitch != 0) ? (int32_t)(batchPara->cropSizeH) : data->srcImageSizeH);
    batchPara->scfInputSizeW = ((batchPara->cropSwitch != 0) ? (int32_t)(batchPara->cropSizeW) : data->srcImageSizeW);

    batchPara->scfSwitch = 1;
    batchPara->scfOutputSizeW = resizeOutputSizeW;
    batchPara->scfOutputSizeH = resizeOutputSizeH;

    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_GetResizePara(void* commPara,
    uint32_t batchIndex, uint32_t* resizeOutputSizeW, uint32_t* resizeOutputSizeH)
{
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);
    if (resizeOutputSizeW == NULL || resizeOutputSizeH == NULL) {
        return HIAI_FAILURE;
    }

    *resizeOutputSizeW = batchPara->scfOutputSizeW;
    *resizeOutputSizeH = batchPara->scfOutputSizeH;

    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_SetPadTopSize(void* commPara, uint32_t batchIndex, uint32_t paddingSizeTop)
{
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);

    batchPara->paddingSwitch = 1;
    batchPara->paddingSizeTop = paddingSizeTop;

    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_SetPadBottomSize(void* commPara, uint32_t batchIndex, uint32_t paddingSizeBottom)
{
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);

    batchPara->paddingSwitch = 1;
    batchPara->paddingSizeBottom = paddingSizeBottom;

    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_SetPadLeftSize(void* commPara, uint32_t batchIndex, uint32_t paddingSizeLeft)
{
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);

    batchPara->paddingSwitch = 1;
    batchPara->paddingSizeLeft = paddingSizeLeft;
    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_SetPadRightSize(void* commPara, uint32_t batchIndex, uint32_t paddingSizeRight)
{
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);

    batchPara->paddingSwitch = 1;
    batchPara->paddingSizeRight = paddingSizeRight;

    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_SetPadChannelValue(
    void* commPara, uint32_t batchIndex, uint32_t chnValue[], uint32_t chnNum)
{
    HIAI_EXPECT_NOT_NULL_R(chnValue, HIAI_FAILURE);
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);
    if (chnNum == 0 || chnNum > MAX_CHANNEL_NUM) {
        return HIAI_FAILURE;
    }
    batchPara->paddingValueChn0 = chnNum >= 1 ? (uint16_t)(chnValue[0]) : 0;
    batchPara->paddingValueChn1 = chnNum >= 2 ? (uint16_t)(chnValue[1]) : 0;
    batchPara->paddingValueChn2 = chnNum >= 3 ? (uint16_t)(chnValue[2]) : 0;
    batchPara->paddingValueChn3 = chnNum == 4 ? (uint16_t)(chnValue[3]) : 0;
    batchPara->paddingSwitch = 1;

    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_GetPadTopSize(void* commPara, uint32_t batchIndex, uint32_t* paddingSizeTop)
{
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);
    HIAI_EXPECT_NOT_NULL_R(paddingSizeTop, HIAI_FAILURE);

    *paddingSizeTop = batchPara->paddingSizeTop;
    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_GetPadBottomSize(void* commPara, uint32_t batchIndex, uint32_t* paddingSizeBottom)
{
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);
    HIAI_EXPECT_NOT_NULL_R(paddingSizeBottom, HIAI_FAILURE);

    *paddingSizeBottom = batchPara->paddingSizeBottom;
    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_GetPadLeftSize(void* commPara, uint32_t batchIndex, uint32_t* paddingSizeLeft)
{
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);
    HIAI_EXPECT_NOT_NULL_R(paddingSizeLeft, HIAI_FAILURE);

    *paddingSizeLeft = batchPara->paddingSizeLeft;
    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_GetPadRightSize(void* commPara, uint32_t batchIndex, uint32_t* paddingSizeRight)
{
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);
    HIAI_EXPECT_NOT_NULL_R(paddingSizeRight, HIAI_FAILURE);

    *paddingSizeRight = batchPara->paddingSizeRight;
    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_GetPadChannelValue(
    void* commPara, uint32_t batchIndex, uint32_t chnValue[], uint32_t chnNum)
{
    HIAI_EXPECT_NOT_NULL_R(chnValue, HIAI_FAILURE);
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);
    if (chnNum == 0 || chnNum > MAX_CHANNEL_NUM) {
        return HIAI_FAILURE;
    }
    uint16_t tmpChnValue[4] = {
        batchPara->paddingValueChn0, batchPara->paddingValueChn1,
        batchPara->paddingValueChn2, batchPara->paddingValueChn3
    };
    for (unsigned int i = 0; i < chnNum; i++) {
        chnValue[i] = (uint32_t)(tmpChnValue[i]);
    }
    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_SetDtcPixelMeanPara(void* commPara, uint32_t batchIndex,
    int32_t pixelMeanPara[], uint32_t chnNum)
{
    HIAI_EXPECT_NOT_NULL_R(pixelMeanPara, HIAI_FAILURE);
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);
    if (chnNum == 0 || chnNum > MAX_CHANNEL_NUM) {
        return HIAI_FAILURE;
    }
    batchPara->dtcPixelMeanChn0 = chnNum >= 1 ? (uint16_t)(pixelMeanPara[0]) : 0;
    batchPara->dtcPixelMeanChn1 = chnNum >= 2 ? (uint16_t)(pixelMeanPara[1]) : 0;
    batchPara->dtcPixelMeanChn2 = chnNum >= 3 ? (uint16_t)(pixelMeanPara[2]) : 0;
    batchPara->dtcPixelMeanChn3 = chnNum == 4 ? (uint16_t)(pixelMeanPara[3]) : 0;

    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_SetDtcPixelMinPara(void* commPara, uint32_t batchIndex,
    float pixelMinPara[], uint32_t chnNum)
{
    HIAI_EXPECT_NOT_NULL_R(pixelMinPara, HIAI_FAILURE);
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);
    if (chnNum == 0 || chnNum > MAX_CHANNEL_NUM) {
        return HIAI_FAILURE;
    }
    batchPara->dtcPixelMinChn0 = chnNum >= 1 ? SaveFp16ToUint16(pixelMinPara[0]) : 0;
    batchPara->dtcPixelMinChn1 = chnNum >= 2 ? SaveFp16ToUint16(pixelMinPara[1]) : 0;
    batchPara->dtcPixelMinChn2 = chnNum >= 3 ? SaveFp16ToUint16(pixelMinPara[2]) : 0;
    batchPara->dtcPixelMinChn3 = chnNum == 4 ? SaveFp16ToUint16(pixelMinPara[3]) : 0;

    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_SetDtcPixelVarReciPara(
    void* commPara, uint32_t batchIndex, float pixelVarReciPara[], uint32_t chnNum)
{
    HIAI_EXPECT_NOT_NULL_R(pixelVarReciPara, HIAI_FAILURE);
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);
    if (chnNum == 0 || chnNum > MAX_CHANNEL_NUM) {
        return HIAI_FAILURE;
    }
    batchPara->dtcPixelVarReciChn0 = chnNum >= 1 ? SaveFp16ToUint16(pixelVarReciPara[0]) : SaveFp16ToUint16(1.0);
    batchPara->dtcPixelVarReciChn1 = chnNum >= 2 ? SaveFp16ToUint16(pixelVarReciPara[1]) : SaveFp16ToUint16(1.0);
    batchPara->dtcPixelVarReciChn2 = chnNum >= 3 ? SaveFp16ToUint16(pixelVarReciPara[2]) : SaveFp16ToUint16(1.0);
    batchPara->dtcPixelVarReciChn3 = chnNum == 4 ? SaveFp16ToUint16(pixelVarReciPara[3]) : SaveFp16ToUint16(1.0);

    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_GetDtcPixelMeanPara(void* commPara, uint32_t batchIndex,
    int32_t pixelMeanPara[], uint32_t chnNum)
{
    HIAI_EXPECT_NOT_NULL_R(pixelMeanPara, HIAI_FAILURE);
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);
    if (chnNum == 0 || chnNum > MAX_CHANNEL_NUM) {
        return HIAI_FAILURE;
    }
    int16_t tmpPixelMeanPara[4] = {
        batchPara->dtcPixelMeanChn0, batchPara->dtcPixelMeanChn1,
        batchPara->dtcPixelMeanChn2, batchPara->dtcPixelMeanChn3
    };
    for (uint32_t i = 0; i < chnNum; i++) {
        pixelMeanPara[i] = (int32_t)(tmpPixelMeanPara[i]);
    }
    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_GetDtcPixelMinPara(void* commPara, uint32_t batchIndex,
    float pixelMinPara[], uint32_t chnNum)
{
    HIAI_EXPECT_NOT_NULL_R(pixelMinPara, HIAI_FAILURE);
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);
    if (chnNum == 0 || chnNum > MAX_CHANNEL_NUM) {
        return HIAI_FAILURE;
    }
    uint16_t tmpPixelMinPara[4] = {
        batchPara->dtcPixelMinChn0, batchPara->dtcPixelMinChn1,
        batchPara->dtcPixelMinChn2, batchPara->dtcPixelMinChn3
    };
    for (uint32_t i = 0; i < chnNum; i++) {
        pixelMinPara[i] = SaveUint16ToFp16(tmpPixelMinPara[i]);
    }
    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_GetDtcPixelVarReciPara(void* commPara, uint32_t batchIndex,
    float pixelVarReciPara[], uint32_t chnNum)
{
    HIAI_EXPECT_NOT_NULL_R(pixelVarReciPara, HIAI_FAILURE);
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);
    if (chnNum == 0 || chnNum > MAX_CHANNEL_NUM) {
        return HIAI_FAILURE;
    }
    uint16_t tmpPixelVarPara[4] = {
        batchPara->dtcPixelVarReciChn0, batchPara->dtcPixelVarReciChn1,
        batchPara->dtcPixelVarReciChn2, batchPara->dtcPixelVarReciChn3
    };
    for (uint32_t i = 0; i < chnNum; i++) {
        pixelVarReciPara[i] = SaveUint16ToFp16(tmpPixelVarPara[i]);
    }
    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_SetRotateAngle(void* commPara, uint32_t batchIndex, float rotateAngle)
{
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);

    if (rotateAngle < 0 || rotateAngle > 360 || (int32_t)(rotateAngle) % 90 >= 1e-5) {
        FMK_LOGE("rotateAngle [%f] is not a multiple of 90 or out of range", rotateAngle);
        return HIAI_FAILURE;
    }
    batchPara->rotateSwitch = (int8_t)(rotateAngle / 90);
    return HIAI_SUCCESS;
}

HIAI_Status HIAI_TensorAippUtil_GetRotateAngle(void* commPara, uint32_t batchIndex, float* rotateAngle)
{
    HIAI_MR_TensorAippBatchPara* batchPara = HIAI_TensorAippUtil_GetBatchPara(commPara, batchIndex);
    HIAI_EXPECT_NOT_NULL_R(batchPara, HIAI_FAILURE);
    HIAI_EXPECT_NOT_NULL_R(rotateAngle, HIAI_FAILURE);

    *rotateAngle = (float)(batchPara->rotateSwitch) * 90;
    return HIAI_SUCCESS;
}
